/******************************************************************************
//             INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in accordance with the terms of that agreement.
//    Copyright(c) 2000 - 2001 Intel Corporation. All Rights Reserved.
//
//  VSS: 
//     $Workfile: $
//     $Revision: $
//     $Date:     $
//     $Archive:  $
//
//  Description:
//      Intel(R) Integrated Performance Primitives - JPEG Helper file.
//      This file contains Inverse DCT functions. 
//
//  History:
//     Date         Author        Changes
//     2000/5/18   Jerry Hu       Created  (Version 0.1, Lee algorithm )
//     2000/12/22  Jerry Hu       Modified (Version 0.2, Winograd algorithm)
//
********************************************************************************/
#include "_ippjpeg.h"

/*
// cos ((2*pi)/16) = 0.9238795325112867561
// cos ((6*pi)/16) = 0.3826834323650897717
// cos ((2*pi)/16) + cos ((6*pi)/16) = 
//                   1.3065629648763765278
// cos ((2*pi)/16) - cos ((6*pi)/16) = 
//                   0.5411961001461969844
*/

#define _SQRT2_2  2896 /* sqrt(2)/2 */
#define _C_2A6_16 5352 /* cos ((2*pi)/16) + cos ((6*pi)/16) */
#define _C_2S6_16 2217 /* cos ((2*pi)/16) - cos ((6*pi)/16) */
#define _C_6_16   1567 /* cos ((6*pi)/16) */

#define _CONSTFACTOR  12
#define _PRESHIFT     6
#define _POSTSHIFT    6


/******************************************************************************
// Name:             ippiDCTQuantInv_JPEG_16s_I
// Description:      Performs Inverse DCT and quantization for single block.
// Input Arguments: 
//          pSrcDst: Identifies source data in 8x8.
//      pQuantTable: Identifies quantization table which was generated by
//                   ippiDCTQuantInvTableInit_JPEG_16u32s.
//
// Output Arguments:
//          pSrcDst: Identifies destination data in 8x8.
//                  
// Remarks:      
//                   1. The start address of "pSrcDst" and  " pQuantTable"
//                      shall be aligned at 4byte boundary.
//                   2. It is better to do this alignment at 32byte boundary to optimize 
//                      D-Cache accessing.
//                   
// Returns:         
//    IPP_STATUS_OK: Succeeds.
//
******************************************************************************/
IPPFUN(IppStatus, ippiDCTQuantInv_JPEG_16s_I) (Ipp16s* pSrcDst, 
                                               const Ipp32s *pQuantTable)
{
    int i;
    int d0,d1,d2,d3,d4,d5,d6,d7;
    int c0,c1,c2,c3,c4,c5,c6,c7;
    int e0, e1, e2, e3, a,b,c,d;
    int value;
    Ipp16s *pSrc, *pDst;
    Ipp32s pTempBuf[64];
    Ipp32s *pTempPtr;

    _IPP_CHECK_ARG(NULL!=pSrcDst);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pSrcDst));
    _IPP_CHECK_ARG(NULL!=pQuantTable);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pQuantTable));

    pTempPtr=pTempBuf;
    pSrc=pSrcDst;

    for (i=8; i>0; i--) {
        d0 = (pSrc[0]*pQuantTable[0]);

        if ( (pSrc[1] | pSrc[2] | pSrc[3] | pSrc[4] |
              pSrc[5] | pSrc[6] | pSrc[7]) == 0 ){

            d0 >>= _PRESHIFT;

            pTempPtr[0] = d0;
            pTempPtr[1] = d0;
            pTempPtr[2] = d0;
            pTempPtr[3] = d0;
            pTempPtr[4] = d0;
            pTempPtr[5] = d0;
            pTempPtr[6] = d0;
            pTempPtr[7] = d0;

        } else {

            /*d0=(pSrc[0]*pQuantTable[0]);*/
            d1=(pSrc[1]*pQuantTable[1]);
            d2=(pSrc[2]*pQuantTable[2]);
            d3=(pSrc[3]*pQuantTable[3]);
            d4=(pSrc[4]*pQuantTable[4]);
            d5=(pSrc[5]*pQuantTable[5]);
            d6=(pSrc[6]*pQuantTable[6]);
            d7=(pSrc[7]*pQuantTable[7]);

            c0=(d0+d4)>>_PRESHIFT;
            c1=(d0-d4)>>_PRESHIFT;

            c2=(((d2-d6)>>_PRESHIFT)*_SQRT2_2)>>(_CONSTFACTOR);
            c3=((d2+d6)>>_PRESHIFT)+c2;

            a=(d1+d7)>>_PRESHIFT;
            b=(d5+d3)>>_PRESHIFT;
            c=(d5-d3)>>_PRESHIFT;
            d=(d1-d7)>>_PRESHIFT;

            value=(d-c)*_C_6_16;
            c4=(c*_C_2A6_16+value)>>_CONSTFACTOR;
            c7=(d*_C_2S6_16+value)>>_CONSTFACTOR;

            value=((a-b)*_SQRT2_2)>>_CONSTFACTOR;
            c5=value+c4;
            c6=value+c7;
            c7=a+b+c7;

            e0=c0+c3;
            e1=c1+c2;
            e2=c1-c2;
            e3=c0-c3;

            pTempPtr[0]=(Ipp32s)(e0+c7);
            pTempPtr[1]=(Ipp32s)(e1+c6);
            pTempPtr[2]=(Ipp32s)(e2+c5);
            pTempPtr[3]=(Ipp32s)(e3+c4);
            pTempPtr[4]=(Ipp32s)(e3-c4);
            pTempPtr[5]=(Ipp32s)(e2-c5);
            pTempPtr[6]=(Ipp32s)(e1-c6);
            pTempPtr[7]=(Ipp32s)(e0-c7);
        }

        pSrc+=8;
        pTempPtr+=8;
        pQuantTable+=8;
    }

    pTempPtr=pTempBuf;
    pDst=pSrcDst;

    for (i=8; i>0; i--) {

        c0=pTempPtr[0*8]+pTempPtr[4*8];
        c1=pTempPtr[0*8]-pTempPtr[4*8];

        c2=((pTempPtr[2*8]-pTempPtr[6*8])*_SQRT2_2)>>_CONSTFACTOR;
        c3=(pTempPtr[2*8]+pTempPtr[6*8])+c2;

        a=pTempPtr[1*8]+pTempPtr[7*8];
        b=pTempPtr[5*8]+pTempPtr[3*8];
        c=pTempPtr[5*8]-pTempPtr[3*8];
        d=pTempPtr[1*8]-pTempPtr[7*8];

        value=(d-c)*_C_6_16;
        c4=(c*_C_2A6_16+value)>>_CONSTFACTOR;
        c7=(d*_C_2S6_16+value)>>_CONSTFACTOR;

        value=((a-b)*_SQRT2_2)>>_CONSTFACTOR;;
        c5=value+c4;
        c6=value+c7;
        c7=a+b+c7;

        e0=c0+c3;
        e1=c1+c2;
        e2=c1-c2;
        e3=c0-c3;

        pDst[0*8]=(Ipp16s)((e0+c7)>>_POSTSHIFT);
        pDst[1*8]=(Ipp16s)((e1+c6)>>_POSTSHIFT);
        pDst[2*8]=(Ipp16s)((e2+c5)>>_POSTSHIFT);
        pDst[3*8]=(Ipp16s)((e3+c4)>>_POSTSHIFT);
        pDst[4*8]=(Ipp16s)((e3-c4)>>_POSTSHIFT);
        pDst[5*8]=(Ipp16s)((e2-c5)>>_POSTSHIFT);
        pDst[6*8]=(Ipp16s)((e1-c6)>>_POSTSHIFT);
        pDst[7*8]=(Ipp16s)((e0-c7)>>_POSTSHIFT);

        pTempPtr++;
        pDst++;
    }

    return IPP_STATUS_OK;
}

/******************************************************************************
// Name:             ippiDCTQuantInv_JPEG_16s
// Description:      Performs Inverse DCT and quantization for single block.
// Input Arguments: 
//             pSrc: Identifies source data in 8x8.
//      pQuantTable: Identifies quantization table which was generated by
//                   ippiDCTQuantInvTableInit_JPEG_16u32s.
//
// Output Arguments:
//             pDst: Identifies destination data in 8x8.
//                  
// Remarks:      
//                   1. The start address of "pSrc", "pDst" and "pQuantTable"
//                      shall be aligned at 4byte boundary.
//                   2. It is better to do this alignment at 32byte boundary to optimize 
//                      D-Cache accessing.
//                   
// Returns:         
//    IPP_STATUS_OK: Succeeds.
//
******************************************************************************/
IPPFUN(IppStatus, ippiDCTQuantInv_JPEG_16s) (const Ipp16s* pSrc, 
                                            Ipp16s *pDst, 
                                            const Ipp32s *pQuantTable)
{
    int i;
    int d0,d1,d2,d3,d4,d5,d6,d7;
    int c0,c1,c2,c3,c4,c5,c6,c7;
    int e0, e1, e2, e3, a,b,c,d;
    int value;
    Ipp32s pTempBuf[64];
    Ipp32s *pTempPtr;

    _IPP_CHECK_ARG(NULL!=pSrc);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pSrc));
    _IPP_CHECK_ARG(NULL!=pDst);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pDst));
    _IPP_CHECK_ARG(NULL!=pQuantTable);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pQuantTable));

    pTempPtr=pTempBuf;

    for (i=8; i>0; i--) {
        d0 = (pSrc[0]*pQuantTable[0]);

        if ( (pSrc[1] | pSrc[2] | pSrc[3] | pSrc[4] |
              pSrc[5] | pSrc[6] | pSrc[7]) == 0 ){
            d0 >>= _PRESHIFT;

            pTempPtr[0] = d0;
            pTempPtr[1] = d0;
            pTempPtr[2] = d0;
            pTempPtr[3] = d0;
            pTempPtr[4] = d0;
            pTempPtr[5] = d0;
            pTempPtr[6] = d0;
            pTempPtr[7] = d0;

        } else {
            /*d0=(pSrc[0]*pQuantTable[0]);*/
            d1=(pSrc[1]*pQuantTable[1]);
            d2=(pSrc[2]*pQuantTable[2]);
            d3=(pSrc[3]*pQuantTable[3]);
            d4=(pSrc[4]*pQuantTable[4]);
            d5=(pSrc[5]*pQuantTable[5]);
            d6=(pSrc[6]*pQuantTable[6]);
            d7=(pSrc[7]*pQuantTable[7]);

            c0=(d0+d4)>>_PRESHIFT;
            c1=(d0-d4)>>_PRESHIFT;

            c2=(((d2-d6)>>_PRESHIFT)*_SQRT2_2)>>(_CONSTFACTOR);
            c3=((d2+d6)>>_PRESHIFT)+c2;

            a=(d1+d7)>>_PRESHIFT;
            b=(d5+d3)>>_PRESHIFT;
            c=(d5-d3)>>_PRESHIFT;
            d=(d1-d7)>>_PRESHIFT;

            value=(d-c)*_C_6_16;
            c4=(c*_C_2A6_16+value)>>_CONSTFACTOR;
            c7=(d*_C_2S6_16+value)>>_CONSTFACTOR;

            value=((a-b)*_SQRT2_2)>>_CONSTFACTOR;
            c5=value+c4;
            c6=value+c7;
            c7=a+b+c7;

            e0=c0+c3;
            e1=c1+c2;
            e2=c1-c2;
            e3=c0-c3;

            pTempPtr[0]=(Ipp32s)(e0+c7);
            pTempPtr[1]=(Ipp32s)(e1+c6);
            pTempPtr[2]=(Ipp32s)(e2+c5);
            pTempPtr[3]=(Ipp32s)(e3+c4);
            pTempPtr[4]=(Ipp32s)(e3-c4);
            pTempPtr[5]=(Ipp32s)(e2-c5);
            pTempPtr[6]=(Ipp32s)(e1-c6);
            pTempPtr[7]=(Ipp32s)(e0-c7);
        }
        pSrc+=8;
        pTempPtr+=8;
        pQuantTable+=8;
    }

    pTempPtr=pTempBuf;

    for (i=8; i>0; i--) {

        c0=pTempPtr[0*8]+pTempPtr[4*8];
        c1=pTempPtr[0*8]-pTempPtr[4*8];

        c2=((pTempPtr[2*8]-pTempPtr[6*8])*_SQRT2_2)>>_CONSTFACTOR;
        c3=(pTempPtr[2*8]+pTempPtr[6*8])+c2;

        a=pTempPtr[1*8]+pTempPtr[7*8];
        b=pTempPtr[5*8]+pTempPtr[3*8];
        c=pTempPtr[5*8]-pTempPtr[3*8];
        d=pTempPtr[1*8]-pTempPtr[7*8];

        value=(d-c)*_C_6_16;
        c4=(c*_C_2A6_16+value)>>_CONSTFACTOR;
        c7=(d*_C_2S6_16+value)>>_CONSTFACTOR;

        value=((a-b)*_SQRT2_2)>>_CONSTFACTOR;;
        c5=value+c4;
        c6=value+c7;
        c7=a+b+c7;

        e0=c0+c3;
        e1=c1+c2;
        e2=c1-c2;
        e3=c0-c3;

        pDst[0*8]=(Ipp16s)((e0+c7)>>_POSTSHIFT);
        pDst[1*8]=(Ipp16s)((e1+c6)>>_POSTSHIFT);
        pDst[2*8]=(Ipp16s)((e2+c5)>>_POSTSHIFT);
        pDst[3*8]=(Ipp16s)((e3+c4)>>_POSTSHIFT);
        pDst[4*8]=(Ipp16s)((e3-c4)>>_POSTSHIFT);
        pDst[5*8]=(Ipp16s)((e2-c5)>>_POSTSHIFT);
        pDst[6*8]=(Ipp16s)((e1-c6)>>_POSTSHIFT);
        pDst[7*8]=(Ipp16s)((e0-c7)>>_POSTSHIFT);

        pTempPtr++;
        pDst++;
    }

    return IPP_STATUS_OK;
}


/******************************************************************************
// Name:             ippiDCTQuantLSInv_JPEG_16s8u
// Description:      Performs Inverse DCT and quantization for single block.
// Input Arguments: 
//             pSrc: Identifies source data in 8x8.
//      pQuantTable: Identifies quantization table which was generated by
//                   ippiDCTQuantInvTableInit_JPEG_16u32s.
//
// Output Arguments:
//             pDst: Identifies destination data in 8x8.
//                  
// Remarks:      
//                   1. The start address of "pSrc", "pDst" and "pQuantTable"
//                      shall be aligned at 4byte boundary.
//                   2. It is better to do this alignment at 32byte boundary to optimize 
//                      D-Cache accessing.
//                   
// Returns:         
//    IPP_STATUS_OK: Succeeds.
//
******************************************************************************/
IPPFUN(IppStatus, ippiDCTQuantLSInv_JPEG_16s8u) (const Ipp16s* pSrc, 
                                                 Ipp8u *pDst,
                                                 int   dstStep,
                                                 const Ipp32s *pQuantTable)
{
    int i;
    int d0,d1,d2,d3,d4,d5,d6,d7;
    int c0,c1,c2,c3,c4,c5,c6,c7;
    int e0, e1, e2, e3, a,b,c,d;
    int value;
    Ipp32s pTempBuf[64];
    Ipp32s *pTempPtr;

    _IPP_CHECK_ARG(NULL!=pSrc);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pSrc));
    _IPP_CHECK_ARG(NULL!=pDst);
    _IPP_CHECK_ARG(0!=dstStep);
    _IPP_CHECK_ARG(NULL!=pQuantTable);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pQuantTable));

    pTempPtr=pTempBuf;

    for (i=8; i>0; i--) {
        d0 = (pSrc[0]*pQuantTable[0]);

        if ( (pSrc[1] | pSrc[2] | pSrc[3] | pSrc[4] |
              pSrc[5] | pSrc[6] | pSrc[7]) == 0 ){
            d0 >>= _PRESHIFT;

            pTempPtr[0] = d0;
            pTempPtr[1] = d0;
            pTempPtr[2] = d0;
            pTempPtr[3] = d0;
            pTempPtr[4] = d0;
            pTempPtr[5] = d0;
            pTempPtr[6] = d0;
            pTempPtr[7] = d0;

        } else {
            /*d0=(pSrc[0]*pQuantTable[0]);*/
            d1=(pSrc[1]*pQuantTable[1]);
            d2=(pSrc[2]*pQuantTable[2]);
            d3=(pSrc[3]*pQuantTable[3]);
            d4=(pSrc[4]*pQuantTable[4]);
            d5=(pSrc[5]*pQuantTable[5]);
            d6=(pSrc[6]*pQuantTable[6]);
            d7=(pSrc[7]*pQuantTable[7]);

            c0=(d0+d4)>>_PRESHIFT;
            c1=(d0-d4)>>_PRESHIFT;

            c2=(((d2-d6)>>_PRESHIFT)*_SQRT2_2)>>(_CONSTFACTOR);
            c3=((d2+d6)>>_PRESHIFT)+c2;

            a=(d1+d7)>>_PRESHIFT;
            b=(d5+d3)>>_PRESHIFT;
            c=(d5-d3)>>_PRESHIFT;
            d=(d1-d7)>>_PRESHIFT;

            value=(d-c)*_C_6_16;
            c4=(c*_C_2A6_16+value)>>_CONSTFACTOR;
            c7=(d*_C_2S6_16+value)>>_CONSTFACTOR;

            value=((a-b)*_SQRT2_2)>>_CONSTFACTOR;
            c5=value+c4;
            c6=value+c7;
            c7=a+b+c7;

            e0=c0+c3;
            e1=c1+c2;
            e2=c1-c2;
            e3=c0-c3;

            pTempPtr[0]=(Ipp32s)(e0+c7);
            pTempPtr[1]=(Ipp32s)(e1+c6);
            pTempPtr[2]=(Ipp32s)(e2+c5);
            pTempPtr[3]=(Ipp32s)(e3+c4);
            pTempPtr[4]=(Ipp32s)(e3-c4);
            pTempPtr[5]=(Ipp32s)(e2-c5);
            pTempPtr[6]=(Ipp32s)(e1-c6);
            pTempPtr[7]=(Ipp32s)(e0-c7);
        }
        pSrc+=8;
        pTempPtr+=8;
        pQuantTable+=8;
    }

    pTempPtr=pTempBuf;

    for (i=8; i>0; i--) {

        c0=pTempPtr[0*8]+pTempPtr[4*8];
        c1=pTempPtr[0*8]-pTempPtr[4*8];

        c2=((pTempPtr[2*8]-pTempPtr[6*8])*_SQRT2_2)>>_CONSTFACTOR;
        c3=(pTempPtr[2*8]+pTempPtr[6*8])+c2;

        a=pTempPtr[1*8]+pTempPtr[7*8];
        b=pTempPtr[5*8]+pTempPtr[3*8];
        c=pTempPtr[5*8]-pTempPtr[3*8];
        d=pTempPtr[1*8]-pTempPtr[7*8];

        value=(d-c)*_C_6_16;
        c4=(c*_C_2A6_16+value)>>_CONSTFACTOR;
        c7=(d*_C_2S6_16+value)>>_CONSTFACTOR;

        value=((a-b)*_SQRT2_2)>>_CONSTFACTOR;;
        c5=value+c4;
        c6=value+c7;
        c7=a+b+c7;

        e0=c0+c3;
        e1=c1+c2;
        e2=c1-c2;
        e3=c0-c3;

        value=((e0+c7)>>_POSTSHIFT);
        pDst[0*dstStep]=_IPP_SHIFTLEVEL_16S8U(value);
        value=((e1+c6)>>_POSTSHIFT);
        pDst[1*dstStep]=_IPP_SHIFTLEVEL_16S8U(value);
        value=((e2+c5)>>_POSTSHIFT);
        pDst[2*dstStep]=_IPP_SHIFTLEVEL_16S8U(value);
        value=((e3+c4)>>_POSTSHIFT);
        pDst[3*dstStep]=_IPP_SHIFTLEVEL_16S8U(value);
        value=((e3-c4)>>_POSTSHIFT);
        pDst[4*dstStep]=_IPP_SHIFTLEVEL_16S8U(value);
        value=((e2-c5)>>_POSTSHIFT);
        pDst[5*dstStep]=_IPP_SHIFTLEVEL_16S8U(value);
        value=((e1-c6)>>_POSTSHIFT);
        pDst[6*dstStep]=_IPP_SHIFTLEVEL_16S8U(value);
        value=((e0-c7)>>_POSTSHIFT);
        pDst[7*dstStep]=_IPP_SHIFTLEVEL_16S8U(value);

        pTempPtr++;
        pDst++;
    }

    return IPP_STATUS_OK;
}

/* EOF */
